package com.yy.okhttp;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * User: gongyongfeng2@yy.com
 * Date: 2020/7/27 16 :00
 */
public class Dispatcher {
    //最多同时请求的数量
    private int maxRequests;
    //一个host的最多的请求数量
    private int maxRequestPerPost;

    private ExecutorService mExecutorService;

    private Deque<Call.AsyncCall> readAsyncCalls = new ArrayDeque();

    private Deque<Call.AsyncCall> runningAsyncCalls = new ArrayDeque();

    public Dispatcher() {
        this(64, 2);
    }

    public Dispatcher(int maxRequests, int maxRequestPerPost) {
        this.maxRequests = maxRequests;
        this.maxRequestPerPost = maxRequestPerPost;
    }

    private synchronized ExecutorService createExecutorService() {
        if (mExecutorService == null) {
            mExecutorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(),
                    Utils.threadFactory("YYOkHttp Dispathcer", true));
        }
        return mExecutorService;
    }

    public void enqueue(Call.AsyncCall asyncCall) {
        if (runningAsyncCalls.size() < maxRequests &&
                runningAsyncCallForHost(asyncCall) < maxRequestPerPost) {
            runningAsyncCalls.add(asyncCall);
            mExecutorService.execute(asyncCall);
        } else {
            readAsyncCalls.add(asyncCall);
        }
    }

    private int runningAsyncCallForHost(Call.AsyncCall asyncCall) {
        int result = 0;
        for (Call.AsyncCall call : runningAsyncCalls) {
            if (asyncCall.host().equals(call.host())) {
                result++;
            }
        }
        return result;
    }

    /**
     * 请求结束 移出正在运行队列
     * 并判断是否执行等待队列中的请求
     *
     * @param asyncCall
     */
    public void finished(Call.AsyncCall asyncCall) {
        synchronized (this) {
            runningAsyncCalls.remove(asyncCall);
            //判断是否执行等待队列中的请求
            promoteCalls();
        }
    }

    /**
     * 判断是否执行等待队列中的请求
     */
    private void promoteCalls() {
        //同时请求达到上限
        if (runningAsyncCalls.size() >= maxRequests) {
            return;
        }
        //没有等待执行请求
        if (readAsyncCalls.isEmpty()) {
            return;
        }
        for (Iterator<Call.AsyncCall> i = readAsyncCalls.iterator(); i.hasNext(); ) {
            Call.AsyncCall call = i.next();
            //同一host同时请求为达上限
            if (runningAsyncCallForHost(call) < maxRequestPerPost) {
                i.remove();
                runningAsyncCalls.add(call);
                createExecutorService().execute(call);
            }
            //到达同时请求上限
            if (runningAsyncCalls.size() >= maxRequests) {
                return;
            }
        }
    }
}
